package cn.bonoon.kernel.support.services;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.persistence.Query;
import javax.persistence.TypedQuery;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import cn.bonoon.kernel.bytecode.EntityReader;
import cn.bonoon.kernel.bytecode.QueryConverter;
import cn.bonoon.kernel.descriptors.EntityDescriptor;
import cn.bonoon.kernel.events.ReadEvent;
import cn.bonoon.kernel.filters.VisibleScopeFilter;
import cn.bonoon.kernel.query.QueryLanguageDescriptor;
import cn.bonoon.kernel.support.entities.Persistable;
import cn.bonoon.kernel.support.searcher.Finder;
import cn.bonoon.kernel.support.searcher.ISearcher;
import cn.bonoon.kernel.support.searcher.StandardFinder;
import cn.bonoon.kernel.support.searcher.StandardSearcher;
import cn.bonoon.kernel.support.services.handler.GetDeletableHandler;
import cn.bonoon.kernel.support.services.handler.GetHandler;
import cn.bonoon.kernel.util.ClassHelper;

/**
 * 对应的接口为：{@link SearchService}
 * V3.0
 * 重点处理ifinder
 * @author jackson
 *
 * @param <E>
 */
@SuppressWarnings("unchecked")
public abstract class AbstractSearchService<E extends Persistable> extends ServiceSupport implements SearchService<E> {
	
	protected ISearcher searcher;
	private GetHandler getHandler;
	protected String __allEntities, __orderby;
	protected VisibleScopeFilter scopeFilter;

	protected Class<E> domainClass;
	
//	protected ISearcher _getSearcher(){
//		if(null == searcher){
//			searcher = SearcherFactory.getFactory().register(applicationContext, domainClass);
//		}
//		return searcher;
//	}
	
	@Override
	public void afterPropertiesSet() throws Exception {
		domainClass = ClassHelper.getActualTypeArgument(getClass(), AbstractSearchService.class, 0);
		Assert.notNull(domainClass, "无法解释实体！");
		
		searcher = _register(domainClass);
		
		internalInit(domainClass);
	}
	
	@Override
	public ISearcher getSearcher() {
		return searcher;
	}
	
	/**
	 * Returns the domain class to handle.
	 * 
	 * @return the domain class
	 */
	public Class<E> getDomainClass() {
		return domainClass;
	}

	/**
	 * getDomainClass().getSimpleName();
	 * @return getDomainClass().getSimpleName();
	 */
	protected String getClassName() {
		return domainClass.getSimpleName();
	}

	public E newInstance() throws Exception{
		return domainClass.newInstance();
	}

	@Override
	public <O> O get(ReadEvent event, Long id, Class<O> type) throws Exception {
		scopeFilter.check(event, entityManager, domainClass, id);
		return (O)searcher.getEntityReader(type).read(event, entityManager, id);
	}

	/**
	 * <font color='red'>
	 * 注意：在service的实现里不允许调本方法，请使用{@link AbstractSearchService#__get(Long)}代替
	 * </font>
	 */
	@Override
	@Transactional(readOnly = true)
	public E get(Long id) {
		E entity = __get(id);
		if(getHandler.handler(entity)){
			return entity;
		}
		return null;
	}

	protected E __get(Long id){
		return entityManager.find(domainClass, id);
	}

	/**
	 * <pre>
	 * 查询解析器的创建，子类可以创建自定义的查询解析器
	 * </pre>
	 * @param entityClass
	 * @return
	 */
	protected StandardSearcher build(Class<E> entityClass){
		return new StandardSearcher(entityClass, applicationContext);
	}
	
	/**
	 * <pre>
	 * spring初始化后调用，主要是对数据库实体对象操作的一些设置，如：移动、添加、删除等操作
	 * </pre>
	 * @param entityClass
	 */
	protected final void internalInit(Class<E> entityClass) {
		searcher = build(entityClass);
//		searcher.init();
		internalInit(searcher.getEntityDescriptor(), entityClass);
		__allEntities = searcher.allEntities();
		__orderby = searcher.orderby();
	}
	
	private boolean movable;
	private boolean statusable;
	
	public boolean isStatusable() {
		return statusable;
	}
	public boolean isMovable() {
		return movable;
	}
	/**
	 * <pre>
	 * 需要初始化各种数据库实体对象操作的处理器。如：移动、修改等
	 * </pre>
	 * @param entityDescriptor
	 * @param entityClass
	 */
	protected void internalInit(EntityDescriptor entityDescriptor, Class<E> entityClass) {
		statusable = entityDescriptor.is(EntityDescriptor.STATUS);
		
		movable = entityDescriptor.is(EntityDescriptor.MOVABLE);
		if(movable){
			initMovable(entityDescriptor, entityClass);
		}else{
			initUnmovable(entityDescriptor, entityClass);
		}
		if(entityDescriptor.is(EntityDescriptor.DELETABLE)){
			initDeletable(entityDescriptor, entityClass);
		}else{
			initUndeletable(entityDescriptor, entityClass);
		}
		if(entityDescriptor.is(EntityDescriptor.SCOPABLE)){
			//表示该实体的业务逻辑允许使用操作范围限制
			scopeFilter = VisibleScopeFilter.STANDRAD;
		}else{
			scopeFilter = VisibleScopeFilter.EMPTY;
		}
	}
	
	/**
	 * <pre>
	 * 实体为有序实体(即可移动)
	 * </pre>
	 * @param entityDescriptor
	 * @param entityClass
	 */
	protected void initMovable(EntityDescriptor entityDescriptor, Class<E> entityClass){ }
	
	/**
	 * 不可移动的情况
	 * @param entityDescriptor
	 * @param entityClass
	 */
	protected void initUnmovable(EntityDescriptor entityDescriptor, Class<E> entityClass){ }
	
	/**
	 * 逻辑删除的数据库实体
	 * @param entityDescriptor
	 * @param entityClass
	 */
	protected void initDeletable(EntityDescriptor entityDescriptor, Class<E> entityClass){
		getHandler = new GetDeletableHandler();
	}
	
	/**
	 * 不可逻辑删除，即直接删除数据库记录的情况
	 * @param entityDescriptor
	 * @param entityClass
	 */
	protected void initUndeletable(EntityDescriptor entityDescriptor, Class<E> entityClass){
		getHandler = GetHandler.standard;
	}

	protected TypedQuery<E> __parser(QueryLanguageDescriptor descriptor) {
		TypedQuery<E> tqSelect = __query(domainClass, descriptor.toSelect());
		descriptor.parseParameters(tqSelect);
		return tqSelect;
	}
	
	@Override
	public Finder finder(Object condition) throws Exception{
		QueryConverter qc = searcher.getQueryConverter(condition.getClass());
		StandardFinder finder = searcher.finder(this);
		qc.query(finder.getAsmParser(), condition);
		return finder;
	}
	
	@Override
	public Finder finder(Object condition, ReadEvent readEvent, Class<?> resultClassType) throws Exception{
		QueryConverter qc = searcher.getQueryConverter(condition.getClass());
		StandardFinder finder = searcher.finder(this, readEvent, resultClassType);
		scopeFilter.filter(readEvent, finder);
		qc.query(finder.getAsmParser(), condition);
		return finder;
	}
	
	@Override
	public Finder finder(ReadEvent readEvent, Class<?> resultClassType) throws Exception {
		return searcher.finder(this, readEvent, resultClassType);
	}
	
	@Override
	public Finder finder() throws Exception {
		return searcher.finder(this);
	}
	
	@Override
	@Transactional(readOnly = true)
	public List<E> find() {
		return __list(domainClass, __allEntities + __orderby);
	}
	
	@Override
	@Transactional(readOnly = true)
	public List<E> find(String where) {
		return __list(domainClass, __allEntities + where);
	}
	
	protected <O> List<O> __find(ReadEvent re, Class<O> rc, String str) throws Exception{
		EntityReader reader = searcher.getEntityReader(rc);
		StringBuilder sbql = new StringBuilder("select ");
		sbql.append(reader.properties()).append(str);
		Query qt = scopeFilter.filter(re, entityManager, sbql, __orderby);
		List<O> rs = new ArrayList<O>();
		for(Object it : qt.getResultList()){
			rs.add((O)reader.read(re, it));
		}
		return rs;
	}

	@Override
	@Transactional(readOnly = true)
	public <O> List<O> find(ReadEvent readEvent, Class<O> resultClassType) throws Exception{
		return __find(readEvent, resultClassType, __allEntities);
	}
	
	@Override
	public List<E> tryLoadChildren(Long rid) {
		return Collections.emptyList();
	}

	@Override
	public <O> List<O> tryLoadChildren(Long rid, ReadEvent readEvent, Class<O> resultClassType) throws Exception{
		return Collections.emptyList();
	}

	@Override
	public List<E> tryLoadRoot() {
		return Collections.emptyList();
	}

	@Override
	public <O> List<O> tryLoadRoot(ReadEvent readEvent, Class<O> resultClassType) throws Exception{
		return Collections.emptyList();
	}
}
